#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/time.h>
#include <host.h>
#include <ftp.h>
#include <ants.h>
#include <wait_read.h>
#include <config.h>
	
#define _SENT(s, cmd, dest) \
do { \
	if(send(s, cmd, strlen(cmd), 0) != strlen(cmd)) { \
		close(s); \
		sleep(2); \
		goto dest; \
	} \
} while (0)	
	
#define _WAIT(s, state) \
do { \
	while(1) { \
		state = wait_read(s, 30); \
		if(state >= 1) \
			break; \
		printf("waiting timeouts --- retry\n"); \
	} \
} while (0)	
	
#define _RECV(s, data, dest) \
do { \
	if(recv(s, msg_hdr, 1024, 0) <= 0) { \
		printf("read error.\n"); \
		goto dest; \
	} \
} while (0)	
	
#ifdef DEBUG
static void _show_data(char *cmd) {
	printf("%s.\n", cmd);
}
#endif
	
static unsigned short data_port(char *address) {
	char *p;
	int i, j;
	p = address;
	for(i = 0; i < 4; i++) /*skip ip address*/
		p = strstr(p, ",") + 1;
	i = atoi(p);
	p = strstr(p, ",") + 1;
	j = atoi(p) + (i << 8);
	return (unsigned short)j;
}
	
static int connect_ftp(struct mission *pms) {
	char cmd[256];
	char msg_hdr[1024];
	int s, state;
connect_again:
	while(1) {
		if((s = connect_host(pms, pms->port)) <= 0)
			sleep(1);
		else
			break;
		printf("connect host again.\n");
	}
	
	_WAIT(s, state);
	_RECV(s, msg_hdr, connect_again); /*skip welcome information*/
#ifdef DEBUG
	_show_data(msg_hdr);
#endif
	
	BUILD_USER(cmd, pms->user);
	_SENT(s, cmd, connect_again);
	_WAIT(s, state);
	_RECV(s, msg_hdr, connect_again);
#ifdef DEBUG
	_show_data(msg_hdr);
#endif
	
	BUILD_PASS(cmd, pms->pass);
	_SENT(s, cmd, connect_again);
	_WAIT(s, state);
	_RECV(s, msg_hdr, connect_again);
#ifdef DEBUG
	_show_data(msg_hdr);
#endif
	if(strstr(msg_hdr, "421 No more connection") != NULL) {
		close(s);
		/* need add fixup code here of bad password.*/
		goto connect_again;
	}
	if((strstr(msg_hdr, "230") == 0) && (strstr(msg_hdr, "200") == 0))
		return -1;
		
	while(1) { /*skip infomation packet*/
		if((strstr(msg_hdr, "Login successful")) || (strstr(msg_hdr, "logged in")))
			break;
		recv(s, msg_hdr, 1024, 0);
	}
	return s;
}	
	
int get_ftp_size(struct mission *pms) {
	char cmd[256];
	char msg_hdr[1024];
	char *p;
	int s, state;
get_again:
	s = connect_ftp(pms);
	if(s == -1)
		return -1;
	BUILD_SIZE(cmd, pms->path);
	_SENT(s, cmd, get_again);
	_WAIT(s, state);
	_RECV(s, msg_hdr, get_again);
#ifdef DEBUG
	_show_data(msg_hdr);
#endif
	p = strstr(msg_hdr, " "); /*space*/
	state = atoi(++p);
	printf("file size is %d\n", state);
	pms->flag = BREAKPOINT;
	return state;
}	
	
void down_ftp_init(struct mission *pms) {
	char cmd[256];
	char msg_hdr[1024];
	unsigned short port;
	int s, s_data, state;
	struct ants *ant;
	int i, thread;
	thread = pms->thread;
	ant = pms->first_ant;
	for(i = 0; i < thread; i++) {
init_again:
		s = connect_ftp(pms);
		
		BUILD_TYPE(cmd);
		_SENT(s, cmd, init_again);
		_WAIT(s, state);
		_RECV(s, msg_hdr, init_again);
#ifdef DEBUG
		_show_data(msg_hdr);
#endif
	
		BUILD_PASV(cmd);
		_SENT(s, cmd, init_again);
		_WAIT(s, state);
		_RECV(s, msg_hdr, init_again);
#ifdef DEBUG
		_show_data(msg_hdr);
#endif
		port = data_port(msg_hdr);
		s_data = connect_host(pms, port);
		if(s_data == -1)
			return;
		
		BUILD_REST(cmd, ant->position);
		_SENT(s, cmd, init_again);
		_WAIT(s, state);
		_RECV(s, msg_hdr, init_again);
#ifdef DEBUG
		_show_data(msg_hdr);
#endif
	
		BUILD_RETR(cmd, pms->path);
		_SENT(s, cmd, init_again);
		_WAIT(s, state);
		_RECV(s, msg_hdr, init_again);
#ifdef DEBUG
		_show_data(msg_hdr);
#endif
		ant->s_c = s;
		ant->s = s_data;
		ant++;
	}	
	return;
}	
